package com.xiuxia.bopicturebackend.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiuxia.bopicturebackend.exception.BusinessException;
import com.xiuxia.bopicturebackend.exception.ErrorCode;
import com.xiuxia.bopicturebackend.exception.ThrowUtils;
import com.xiuxia.bopicturebackend.model.dto.space.analyze.*;
import com.xiuxia.bopicturebackend.model.entity.Picture;
import com.xiuxia.bopicturebackend.model.entity.Space;
import com.xiuxia.bopicturebackend.model.entity.User;
import com.xiuxia.bopicturebackend.model.vo.space.analyze.*;
import com.xiuxia.bopicturebackend.service.PictureService;
import com.xiuxia.bopicturebackend.service.SpaceAnalyzeService;
import com.xiuxia.bopicturebackend.service.SpaceService;
import com.xiuxia.bopicturebackend.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @ClassName SpaceAnalyzeServiceImpl
 * @Author CHENBO
 * @Date 2025/7/16 9:30
 */
@Service
public class SpaceAnalyzeServiceImpl implements SpaceAnalyzeService {
    @Resource
    private UserService userService;
    @Resource
    private SpaceService spaceService;
    @Autowired
    private PictureService pictureService;

    /**
     * 检查空间分析权限
     *
     * @param spaceAnalyzeRequestDTO 空间分析请求体
     * @param loginUser              登录用户
     */
    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequestDTO spaceAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        if (spaceAnalyzeRequestDTO.isQueryAll() || spaceAnalyzeRequestDTO.isQueryPublic()) {
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权访问公共图库");
        } else {
            Long spaceId = spaceAnalyzeRequestDTO.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(loginUser, space);
        }
    }

    /**
     * 根据分析范围构建查询条件
     *
     * @param spaceAnalyzeRequest 分析请求体
     * @param queryWrapper        查询条件
     */
    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequestDTO spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
        if (spaceAnalyzeRequest.isQueryAll()) {
            return;
        }
        if (spaceAnalyzeRequest.isQueryPublic()) {
            queryWrapper.isNull("spaceId");
            return;
        }
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }

    @Override
    public SpaceUsageAnalyzeResponseVO getSpaceUsageAnalyze(SpaceAnalyzeRequestDTO spaceAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        if (spaceAnalyzeRequestDTO.isQueryAll() || spaceAnalyzeRequestDTO.isQueryPublic()) {
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权访问公共图库");
            LambdaQueryWrapper<Picture> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(Picture::getPicSize);
            if (!spaceAnalyzeRequestDTO.isQueryAll()) {
                queryWrapper.isNull(Picture::getSpaceId);
            }
            List<Object> pictureObjects = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = pictureObjects.stream().mapToLong(result -> result instanceof Long ? (Long) result : 0).sum();
            long usedCount = pictureObjects.size();
            SpaceUsageAnalyzeResponseVO spaceUsageAnalyzeResponseVO = new SpaceUsageAnalyzeResponseVO();
            spaceUsageAnalyzeResponseVO.setUsedSize(usedSize);
            spaceUsageAnalyzeResponseVO.setUsedCount(usedCount);
            // 公共图库无比例无上限
            spaceUsageAnalyzeResponseVO.setMaxSize(null);
            spaceUsageAnalyzeResponseVO.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponseVO.setMaxCount(null);
            spaceUsageAnalyzeResponseVO.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponseVO;
        } else {
            Long spaceId = spaceAnalyzeRequestDTO.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(loginUser, space);
            SpaceUsageAnalyzeResponseVO spaceUsageAnalyzeResponseVO = new SpaceUsageAnalyzeResponseVO();
            spaceUsageAnalyzeResponseVO.setUsedSize(space.getTotalSize());
            spaceUsageAnalyzeResponseVO.setMaxSize(space.getMaxSize());
            double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            spaceUsageAnalyzeResponseVO.setSizeUsageRatio(sizeUsageRatio);
            spaceUsageAnalyzeResponseVO.setUsedCount(space.getTotalCount());
            spaceUsageAnalyzeResponseVO.setMaxCount(space.getMaxCount());
            double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            spaceUsageAnalyzeResponseVO.setCountUsageRatio(countUsageRatio);
            return spaceUsageAnalyzeResponseVO;
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponseVO> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequestDTO spaceCategoryAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceCategoryAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequestDTO, loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequestDTO, queryWrapper);
        queryWrapper.select("category AS category", "COUNT(*) AS count", "SUM(picSize) AS totalSize").groupBy("category");
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(result -> {
                    String category = result.get("category") != null ? result.get("category").toString() : "未分类";
                    Long count = ((Number) result.get("count")).longValue();
                    Long totalSize = ((Number) result.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeResponseVO(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    @Override
    public List<SpaceTagAnalyzeResponseVO> getSpaceTagAnalyze(SpaceTagAnalyzeRequestDTO spaceTagAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceTagAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequestDTO, loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequestDTO, queryWrapper);
        queryWrapper.select("tags");
        List<String> tagJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        Map<String, Long> tagCountMap = tagJsonList.stream()
                .flatMap(tagJson -> JSONUtil.toList(tagJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        return tagCountMap.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeResponseVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeResponseVO> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequestDTO spaceSizeAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceSizeAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequestDTO, loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequestDTO, queryWrapper);
        queryWrapper.select("picSize");
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .map(size -> ((Number) size).longValue())
                .collect(Collectors.toList());
        Map<String, Long> sizeRangeMap = new LinkedHashMap<>();
        sizeRangeMap.put("<100KB", picSizeList.stream().filter(size -> size < 1024 * 100).count());
        sizeRangeMap.put("100KB-500KB", picSizeList.stream().filter(size -> size >= 1024 * 100 && size < 1024 * 500).count());
        sizeRangeMap.put("500KB-1MB", picSizeList.stream().filter(size -> size >= 1024 * 500 && size < 1024 * 1024).count());
        sizeRangeMap.put(">1MB", picSizeList.stream().filter(size -> size > 1024 * 1024 * 5).count());
        return sizeRangeMap.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponseVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeResponseVO> getSpaceUserAnalyze(SpaceUserAnalyzeRequestDTO spaceUserAnalyzeRequestDTO, User loginUser) {
        ThrowUtils.throwIf(spaceUserAnalyzeRequestDTO == null, ErrorCode.PARAMS_ERROR);
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequestDTO, loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        Long userId = spaceUserAnalyzeRequestDTO.getUserId();
        queryWrapper.eq(ObjUtil.isNotNull(userId), "userId", userId);
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequestDTO, queryWrapper);
        // 时间维度
        String timeDimension = spaceUserAnalyzeRequestDTO.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m-%d') AS period", "COUNT(*) AS count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) AS period", "COUNT(*) AS count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m') AS period", "COUNT(*) AS count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "时间维度错误");
        }
        queryWrapper.groupBy("period").orderByAsc("period");
        List<Map<String, Object>> queryResultList = pictureService.getBaseMapper().selectMaps(queryWrapper);
        return queryResultList.stream()
                .map(result -> {
                    String period = result.get("period").toString();
                    Long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeResponseVO(period, count);
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequestDTO spaceRankAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceRankAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        // 仅管理员可查看空间排行
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权查看空间排行");

        // 构造查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "spaceName", "userId", "totalSize")
                .orderByDesc("totalSize")
                .last("LIMIT " + spaceRankAnalyzeRequest.getTopN()); // 取前 N 名

        // 查询结果
        return spaceService.list(queryWrapper);
    }

}
